隨著大家抓的寶可夢越來越多,我們的圖鑑列表或交換介面可能會一口氣塞入數百甚至上千筆資料。如果在 React 中一次把一千張卡片 (DOM 節點) 全部渲染出來,瀏覽器絕對會卡到懷疑人生!
為了解決這個效能瓶頸,我們導入了 虛擬滾動 (Virtual Scrolling) 技術,而 react-window 便是 React 生態系中最輕量、最強大的解決方案之一。今天我們先來了解它的核心運作原理。
新手常常會把這兩個詞搞混,以為 React 已經有了 Virtual DOM 就不會卡,其實兩者解決的是完全不同的問題:
| 專有名詞 | 運作原理 | 解決的痛點 |
|---|---|---|
| Virtual DOM (虛擬 DOM) | React 內建的機制。在記憶體中比對新舊 UI 的差異,找出「最小變動範圍」後,才去更新真實的 HTML DOM。 | 解決了「頻繁操作真實 DOM 很慢」的問題。但如果您要它一次畫 1000 個 DOM,它還是得乖乖畫 1000 個,這點它幫不了您。 |
| Virtual Scrolling (虛擬滾動) | react-window 的機制。「只渲染你看得見的畫面」。假設有 1000 筆資料,但螢幕高度只能看到 10 筆,它就真的只在 DOM 裡畫 10 個節點,往下滾動時快速抽換裡面的內容。 |
解決了「DOM 節點過多導致瀏覽器記憶體爆滿、滾動卡頓」的問題。 |
這就是為什麼不管你的陣列有 100 筆還是 10 萬筆,搭配了虛擬滾動後,畫面上永遠只有不到 20 個 DOM 節點,效能自然好到飛天!
要使用虛擬滾動,最重要的就是指定外框尺寸與每一列的高度:
// 基本語法示意 (明天會實作進專案)
import { FixedSizeList } from 'react-window';
const Row = ({ index, style }) => (
// 注意:傳入的 style 是靈魂,它透過 position: absolute 與 top 來定位這筆資料該出現在哪裡
<div style={style}>我是第 {index} 隻寶可夢</div>
);
// 限制可視範圍高度為 400px,每一列高度 50px
<FixedSizeList height={400} itemCount={1000} itemSize={50} width="100%">
{Row}
</FixedSizeList>

在交換時有許多庫存的寶可夢可選擇時,使用虛擬滾動技術來維持網頁效能。
開啟瀏覽器的開發者工具 (F12) 的 Elements 面板,即使不斷往下捲動,<div class="List">裡面的子節點數量永遠固定維持在那幾個,這畫面非常震撼。
觀念釐清了!明天,我們將打開專案裡的 TradePokemonDialog.tsx,把這個技術真正套用到我們密密麻麻的寶可夢交換列表中!